Creating a Soccer Game
Part 1
Author: Thiago Campos Viana
Contents
Contents............................................................................................2
Image List.........................................................................................2
Script List..........................................................................................3
Part 1: A Simple Soccer Game..............................................................4
1.1 The game window.......................................................................5
1.2 The rules...................................................................................7
1.3 The assets.................................................................................8
1.4 The ball...................................................................................11
1.5 The player positions..................................................................14
Image List
Image 1 - Game Window.....................................................................5
Image 2 - Classes...............................................................................7
Image 3 - Player.................................................................................9
Image 4 - Player Modeling....................................................................9
Image 5 - Player Animation..................................................................9
Image 6 - Unity3d.............................................................................10
Image 7 - Unity3d and the soccer field.................................................11
Image 8 - Defending..........................................................................15
Image 9 - Atacking............................................................................16
2
Script List
Script 1 - BallBehavior.js....................................................................14
Script 2 - SoccerTeam.js....................................................................25
Script 3 - goalTrigger.js.....................................................................27
Script 4 - FreeKickTrigger.js...............................................................28
Script 5 - throwInTrigger.js................................................................29
Script 6 - PCThirdPersonController.js...................................................35
Script 7 - ThirdPersonController.js.......................................................45
3
Part 1: A Simple Soccer Game
This series of tutorials will detail the development of a socer game,
starting with a simple soccer. The first part of the project is based on
Simple Soccer writed by Mat Buckland in his book Programming
Game AI by Example.
The first part of the tutorials has the following objectives:
•
Provide an overview of the game to be developed.
• Create the field, the goals and create the script that records the
occurrence of a goal, side kicks, and corner kicks.
•
Develop the camera control script.
• Create the score field on the game window that will show the
goals on each side of the field.
• Create the game timer.
• Start the development of scripts responsible for controlling the
ball and players.
4
1.1 The game window
Time: 5:00
0-0
B
A
C
Restart Application
Quit Application
D
PlayerName
GK/DF/MF/FW
E
F
MiniMap
4 (n)
PlayerName
GK/DF/MF/FW
4 (n)
Image 1 - Game Window
In this game, the parts of the screen that will be shown are A and B.
Parts C, D, E and F will be coded in a future tutorial. The script to
display the score and the clock is:
// SGUI.js
// You can assign here an object of type GUISkin, which sets the GUI
style.
var gSkin : GUISkin;
private var isLoading = false;
// The variables responsible for storing the amount of goals from each
team.
var teamAScore:int= 0;
var teamBScore:int = 0;
// A float which controls the elapsed time of the match.
5
var timer:float=0;
// Function to show the GUI of the game.
function OnGUI()
{
// If gSkin variable is not null, change the style of GUI.
if(gSkin)
GUI.skin = gSkin;
// Draw the area that will show the team name and score.
GUI.Button( Rect( 15, 20, 220, 30), "", "button");
// Name of the first team, "BRA" - Brazil
var message = "BRA ";
// The score has 2-digits, so the amount of goals goes from 00 to
99.
if (teamAScore < 10 )
message+="0"+teamAScore;
else message+= teamAScore;
// BRA 00 x ..
message+=" x ";
// BRA 00 x 00 ARG
if (teamBScore < 10 )
message+="0"+teamBScore+" ARG";
else message+= teamBScore+" ARG";
// Draw the timer area.
GUI.Label ( Rect( 20, 20, 210, 35),message, "label");
timer += Time.deltaTime;
GUI.Button( Rect( Screen.width - 110, 20, 80, 30), "", "button");
// Shows the timer.
6
if( Mathf.Floor((timer - (Mathf.Floor(timer/60)*60))) < 10)
GUI.Label ( Rect( Screen.width - 105, 20, 100, 35),
"0"+Mathf.Floor(timer/60)+":0"+Mathf.Floor((timer (Mathf.Floor(timer/60)*60))), "label");
else
GUI.Label ( Rect( Screen.width - 105, 20, 100, 35),
"0"+Mathf.Floor(timer/60)+":"+Mathf.Floor((timer (Mathf.Floor(timer/60)*60))), "label");
}
This script should be assigned to the MainCamera object.
1.2 The rules
SoccerPitch
2
2
Goal
SoccerTeam
4
FieldPlayer
1
SoccerBall
1
1
StateMachine
1
1
GoalKeeper
Image 2 - Classes
7
•
In the game, there are two teams. Each team has four players
and a goalkeeper.
•
The field has two goals and one ball.
•
There are no faults.
•
In the event of a goal, the ball goes into the midfield and the
players take their starting positions. The possession of the ball
goes to the team that conceded the goal.
•
In the event of a corner kick or goal kick, the ball goes into
the midfield. The ball possession goes to the team that was not
with the ball possession.
•
In the event of a throw-in. The team that was not in
possession of the ball, has a time to catch the ball and put it
back in play.
1.3 The assets
The models were made with "Blender":
Name
Animations
Player
Running ( ok ),
Kicking,
Scoring,
Waiting.
Ball
none
Pitch
none
Goal
none
Stadium
none
Details
Includes the pitch.
8
Image 3 - Player
Image 4 - Player Modeling
Image 5 - Player Animation
9
Image 6 - Unity3d
10
Image 7 - Unity3d and the soccer field
1.4 The ball
The ball is a GameObject with a rigidbody and a script called
BallBehavior.js.
// BallBehavior.js
// Pointer to the player with the ball.
var myOwner:Transform;
// Store the starting position of the ball.
var iniPosition:Vector3;
// Pointer to the teams.
var teamA:Transform;
var teamB:Transform;
11
var canMove:boolean;
// Variable used in the function keepPosition, that keeps the ball in this
position.
var lastPosition:Vector3;
// Function executed when initializing the object.
function Awake(){
// Start position is set as the position of the ball in the Unity editor.
iniPosition = transform.position;
// The ball can move.
canMove = true;
// Find the team objects.
teamA = GameObject.FindWithTag ("BlueTeam").transform;
teamB = GameObject.FindWithTag ("RedTeam").transform;
lastPosition = iniPosition;
}
// Update function
function Update () {
// Check if the ball can move.
if ( !canMove ){
keepPosition();
return;
}
// If there is one player controlling the ball, the ball must remain in
front of him.
if(myOwner){
transform.position = Vector3(0,transform.position.y,0) +
Vector3(myOwner.position.x,0,myOwner.position.z) +
myOwner.forward*2;
12
if(myOwner.GetComponent(CharacterController).velocity.sqrMagnitude >
10)
transform.RotateAround (transform.position, myOwner.right,
5*Time.deltaTime *
myOwner.GetComponent(CharacterController).velocity.sqrMagnitude);
}
}
// Goal function.
function OnGoal(){
// No player has control of the ball.
myOwner = null;
// Sets the linear velocity of the ball to zero.
rigidbody.velocity = Vector3.zero;
// Sets the angular velocity of the ball to zero.
rigidbody.angularVelocity= Vector3.zero;
// Ball should keep the position until the players take their positions.
canMove= false;
// LastPosition is used in the function keepPosition, keeping the ball
in one point
lastPosition = iniPosition;
}
// Keeps the ball in the lastPosition point.
function keepPosition(){
transform.position=lastPosition;
rigidbody.velocity = Vector3.zero;
rigidbody.angularVelocity= Vector3.zero;
}
13
// ThrowIn function
function OnThrowIn(){
myOwner = null;
rigidbody.velocity = Vector3.zero;
rigidbody.angularVelocity= Vector3.zero;
lastPosition = transform.position;
}
Script 1 - BallBehavior.js
1.5 The player positions
In this tutorial, each team has four players and a goalkeeper,
players assumes two formations, attack and defense, each
represented by a set of empty GameObjects, which are arranged on
the map following a certain pattern. Image 8 shows how these
objects should be placed into the position of defense and Image 9 the
attack.
14
Image 8 - Defending
15
Image 9 - Atacking
// SoccerTeam.js
// O jogador que está sendo controlado no momnento.
var controllingPlayer:Transform;
// O jogador que dará suporte para o jogador que está sendo
controlado.
var supportingPlayer:Transform;
// O jogador mais próximo a bola
var playerClosestToBall:Transform;
// O jogador que irá receber o passe.
var receivingPlayer:Transform;
// O gol adversário, deve ser um GameObject.
var targetGoal:Transform;
// O gol do própio time, também um GameObject.
var homeGoal:Transform;
16
// True para Time controlado pelo pc, false para time controlador
pelo usuário.
var isPC:boolean = true;
// O time está com a bola?
var hasTheBall:boolean;
// Ponteiro para o GameObject do time adversário.
var opponentTeam:Transform;
// Array de GameObjects vazios representando as posições de
ataque e defesa.
var defendingTargets:Transform[];
var attackingTargets:Transform[];
// Ponteiro para a bola.
var soccerBall:Transform;
// O time está no atacando?
var isAttacking:boolean;
// O time está defendendo?
var isDefending:boolean;
// A bola deve sair do meio de campo?
var prepareForKickOff:boolean;
// A bola deve sair da lateral.
var prepareForThrowIn:boolean = false;
// Ponteiro para os jogadores do time.
var players:Transform[];
function Awake(){
// busca o objeto com a tag “SoccerBall” e associa a variável
soccerBall a ele.
17
soccerBall = GameObject.FindWithTag
("SoccerBall").transform;
// Quando o jogo é iniciado, o time está na posição de defesa.
isAttacking = false;
isDefending=true;
// No inicio do jogo, os jogadores devem se posicionar para a
saída de bola.
prepareForKickOff = true;
// Função que adiciona o script PCThirdPersonController para
todos jogadores.
setUpPlayers();
// O jogo inicia com o RedTeam com a posse de bola.
if(transform.tag == "RedTeam"){
opponentTeam = GameObject.FindWithTag
("BlueTeam").transform;
hasTheBall = true;
}
else opponentTeam = GameObject.FindWithTag
("RedTeam").transform;
// Encontro o jogador mais próximo a bola e associa ele com a
variavel playerClosestToBall
findClosestToBall();
controllingPlayer = playerClosestToBall;
// Se o time é controlado pelo usuário, faz com que o
controllingPlayer seja controlado pelo usuário.
if (!isPC) switchController(controllingPlayer);
// Jogadores assumem a posição de defesa.
defendingFormation();
}
18
function setUpPlayers(){
for (var child : Transform in players) {
child.gameObject.AddComponent(PCThirdPersonController);
}
}
function defendingFormation(){
var x = 0;
for (var child : Transform in players) {
if( child != controllingPlayer )
child.GetComponent(PCThirdPersonController).targetPoint =
defendingTargets[x];
else
child.GetComponent(PCThirdPersonController).targetPoint =
soccerBall;
x++;
}
}
function preparingFormation(){
var x = 0;
var script =
controllingPlayer.GetComponent(ThirdPersonController);
if ( script != null ){
controllingPlayer.Destroy(script);
controllingPlayer.GetComponent(PCThirdPersonController).canMove
= true;
19
}
for (var child : Transform in players) {
child.GetComponent(PCThirdPersonController).targetPoint =
defendingTargets[x];
x++;
}
}
function attackingFormation(){
var x = 0;
for (var child : Transform in players) {
if( child != controllingPlayer)
child.GetComponent(PCThirdPersonController).targetPoint =
attackingTargets[x];
else if ( !
controllingPlayer.GetComponent(PCThirdPersonController).playerHa
sTheBall() )
child.GetComponent(PCThirdPersonController).targetPoint =
soccerBall;
else
child.GetComponent(PCThirdPersonController).targetPoint =
targetGoal;
x++;
}
}
// Todos os jogadores estão na sua posição inicial?
function allPlayersAtHome():boolean{
var x = 0;
20
for (var child : Transform in players) {
if ( ( child.position defendingTargets[x].position ).sqrMagnitude > 3 ) return false;
x++;
}
return true;
}
function Update () {
findClosestToBall();
if (prepareForKickOff){
preparingFormation();
if ( allPlayersAtHome() )
{
if( (opponentTeam.GetComponent(SoccerTeam).allPlayersAtHome()
&& hasTheBall ) ||
soccerBall.GetComponent(BallBehavior).myOwner != null )
{
prepareForKickOff = false;
//findClosestToBall();
controllingPlayer = playerClosestToBall;
if (!isPC) switchController(controllingPlayer);
soccerBall.GetComponent(BallBehavior).canMove = true;
}
else
21
return;
}
else
return;
}
if(prepareForThrowIn){
preparingFormation();
if ( soccerBall.GetComponent(BallBehavior).myOwner !=
null )
{
prepareForThrowIn=false;
//findClosestToBall();
controllingPlayer = playerClosestToBall;
if (!isPC) switchController(controllingPlayer);
}
else
return;
}
if ( controllingPlayer != playerClosestToBall ){
var newDistance = (playerClosestToBall.position soccerBall.position).sqrMagnitude;
var oldDistance = (controllingPlayer.position soccerBall.position).sqrMagnitude;
if (isPC || newDistance < oldDistance*0.7)
switchControllingPlayer(playerClosestToBall);
}
22
if ( isDefending ){
//defendendo
//se está no estado de defesa e pega a bola, sai da
defesa e inicia o estado de ataque
if(hasTheBall){
isDefending=false;
isAttacking=true;
attackingFormation();
}
defendingFormation();
} else {
//atacando
//se está no estado de ataque e perde a bola, sai do
ataque e inicia a defesa
if(!hasTheBall){
isDefending=true;
isAttacking=false;
defendingFormation();
}
attackingFormation();
if (isPC){
direction = targetGoal.position controllingPlayer.position;
if (direction.sqrMagnitude < 400)
controllingPlayer.GetComponent(PCThirdPersonController).kick(targ
etGoal);
}
23
}
}
function findClosestToBall(){
var ballSqrDistance= Mathf.Infinity;
for (var child : Transform in players) {
newDistance = (child.position soccerBall.position).sqrMagnitude;
if (newDistance < ballSqrDistance){
playerClosestToBall = child;
ballSqrDistance = newDistance;
}
}
}
function switchControllingPlayer(newControllingPlayer:Transform){
if (!isPC){
switchController(controllingPlayer);
switchController(newControllingPlayer);
}
controllingPlayer = newControllingPlayer;
}
function switchController( soccerPlayer:Transform ){
var newScript;
var oldScript;
if (!soccerPlayer.GetComponent(ThirdPersonController)){
newScript =
soccerPlayer.gameObject.AddComponent(ThirdPersonController);
24
soccerPlayer.GetComponent(PCThirdPersonController).canMove
= false;
}
else
{
soccerPlayer.GetComponent(PCThirdPersonController).canMove
= true;
oldScript =
soccerPlayer.GetComponent(ThirdPersonController);
soccerPlayer.Destroy(oldScript);
}
}
Script 2 - SoccerTeam.js
// goalTrigger.js
var goalTeam:String;
var soccerBall:Transform;
var teamA:Transform;
var teamB:Transform;
function Awake(){
soccerBall = GameObject.FindWithTag
("SoccerBall").transform;
teamA = GameObject.FindWithTag ("BlueTeam").transform;
teamB = GameObject.FindWithTag ("RedTeam").transform;
25
}
function OnTriggerEnter (other : Collider) {
if(other.gameObject.layer==9){
if ( goalTeam=="TeamA" ){
Camera.main.GetComponent(SGUI).teamBScore=Camera.main.Get
Component(SGUI).teamBScore+1;
teamA.GetComponent(SoccerTeam).hasTheBall =
true;
teamB.GetComponent(SoccerTeam).hasTheBall =
false;
} else {
Camera.main.GetComponent(SGUI).teamAScore=Camera.main.Get
Component(SGUI).teamAScore+1;
teamA.GetComponent(SoccerTeam).hasTheBall =
false;
teamB.GetComponent(SoccerTeam).hasTheBall =
true;
}
soccerBall.GetComponent (BallBehavior).OnGoal();
teamA.GetComponent(SoccerTeam).prepareForKickOff =
true;
teamB.GetComponent(SoccerTeam).prepareForKickOff =
true;
26
}
}
Script 3 - goalTrigger.js
// FreeKickTrigger.js
var soccerBall:Transform;
var teamA:Transform;
var teamB:Transform;
function Awake(){
soccerBall = GameObject.FindWithTag
("SoccerBall").transform;
teamA = GameObject.FindWithTag ("BlueTeam").transform;
teamB = GameObject.FindWithTag ("RedTeam").transform;
}
function OnTriggerEnter (other : Collider) {
if(other.gameObject.layer==9){
if ( !teamA.GetComponent(SoccerTeam).hasTheBall ){
teamA.GetComponent(SoccerTeam).hasTheBall =
true;
teamB.GetComponent(SoccerTeam).hasTheBall =
false;
} else {
teamA.GetComponent(SoccerTeam).hasTheBall =
false;
teamB.GetComponent(SoccerTeam).hasTheBall =
true;
}
soccerBall.GetComponent (BallBehavior).OnGoal();
27
teamA.GetComponent(SoccerTeam).prepareForKickOff =
true;
teamB.GetComponent(SoccerTeam).prepareForKickOff =
true;
}
}
Script 4 - FreeKickTrigger.js
// throwInTrigger.js
var soccerBall:Transform;
var teamA:Transform;
var teamB:Transform;
function Awake(){
soccerBall = GameObject.FindWithTag
("SoccerBall").transform;
teamA = GameObject.FindWithTag ("BlueTeam").transform;
teamB = GameObject.FindWithTag ("RedTeam").transform;
}
function OnTriggerEnter (other : Collider) {
if(other.gameObject.layer==9){
soccerBall.GetComponent (BallBehavior).OnThrowIn();
if ( teamA.GetComponent(SoccerTeam).hasTheBall ==
true ){
teamA.GetComponent(SoccerTeam).hasTheBall =
false;
teamB.GetComponent(SoccerTeam).hasTheBall =
true;
28
teamA.GetComponent(SoccerTeam).prepareForThrowIn= true;
} else {
teamA.GetComponent(SoccerTeam).hasTheBall =
true;
teamB.GetComponent(SoccerTeam).hasTheBall =
false;
teamB.GetComponent(SoccerTeam).prepareForThrowIn =
true;
}
}
}
Script 5 - throwInTrigger.js
// PCThirdPersonController.js
var soccerBall:Transform;
// The speed when walking
var walkSpeed = 3.0;
// when pressing "Fire3" button (cmd) we start running
var runSpeed = 6.0;
var kickSpeed = 40;
var passSpeed = 20;
var rotateSpeed = 500.0;
var targetPoint:Transform;
29
var canMove:boolean = true;
// The last collision flags returned from controller.Move
private var collisionFlags : CollisionFlags;
private var isControllable = true;
function Awake ()
{
soccerBall = GameObject.FindWithTag
("SoccerBall").transform;
//targetPoint = soccerBall;
}
// This next function responds to the "HidePlayer" message by
hiding the player.
// The message is also 'replied to' by identically-named functions in
the collision-handling scripts.
// - Used by the LevelStatus script when the level completed
animation is triggered.
function HidePlayer()
{
GameObject.Find("rootJoint").GetComponent(SkinnedMeshRenderer
).enabled = false; // stop rendering the player.
isControllable = false; // disable player controls.
}
// This is a complementary function to the above. We don't use it in
the tutorial, but it's included for
// the sake of completeness. (I like orthogonal APIs; so sue me!)
function ShowPlayer()
{
30
GameObject.Find("rootJoint").GetComponent(SkinnedMeshRenderer
).enabled = true; // start rendering the player again.
isControllable = true; // allow player to control the character
again.
}
function Update() {
if (canMove){
direction = targetPoint.position - transform.position;
direction.y = 0;
if (direction.sqrMagnitude > 2){
// Rotate towards the target
transform.rotation = Quaternion.Slerp
(transform.rotation, Quaternion.LookRotation(direction),
rotateSpeed * Time.deltaTime);
transform.eulerAngles = Vector3(0,
transform.eulerAngles.y, 0);
// Modify speed so we slow down when we are not
facing the target
var forward =
transform.TransformDirection(Vector3.forward);
var speedModifier = Vector3.Dot(forward,
direction.normalized);
speedModifier = Mathf.Clamp01(speedModifier);
// Move the character
31
direction = forward * runSpeed * speedModifier;
GetComponent
(CharacterController).SimpleMove(direction);
}
}
}
function OnControllerColliderHit (hit : ControllerColliderHit )
{
if (hit.rigidbody == soccerBall.rigidbody){
if (!playerHasTheBall() ||
soccerBall.rigidbody.GetComponent("BallBehavior").myOwner ==
null){
soccerBall.rigidbody.GetComponent("BallBehavior").myOwner
= transform;
transform.parent.GetComponent(SoccerTeam).hasTheBall =
true;
transform.parent.GetComponent(SoccerTeam).opponentTeam.GetC
omponent(SoccerTeam).hasTheBall = false;
}
}
}
function playerHasTheBall():boolean{
return
(soccerBall.rigidbody.GetComponent("BallBehavior").myOwner ==
transform);
}
32
function Reset ()
{
gameObject.tag = "Player";
}
function kick(kickTarget:Transform){
var targetDir = kickTarget.position - transform.position;
if
(soccerBall.rigidbody.GetComponent("BallBehavior").myOwner ==
transform ){
if( Vector3.Angle (transform.forward, targetDir)
<130 ){
soccerBall.rigidbody.GetComponent("BallBehavior").rigidbody.velocit
y =targetDir.normalized*kickSpeed;
soccerBall.rigidbody.GetComponent("BallBehavior").myOwner
= null;
}
}
}
function pass(receiver:Transform){
var targetDir = receiver.position - transform.position;
if
(soccerBall.rigidbody.GetComponent("BallBehavior").myOwner ==
transform ){
if( Vector3.Angle (transform.forward,
targetDir) <130 ){
33
soccerBall.rigidbody.GetComponent("BallBehavior").rigidbody.velocit
y = targetDir.normalized*passSpeed;
soccerBall.rigidbody.GetComponent("BallBehavior").myOwner
= null;
}
else
soccerBall.rigidbody.GetComponent("BallBehavior").rigidbody.velocit
y = transform.TransformDirection(Vector3(0,0,passSpeed));
soccerBall.rigidbody.GetComponent("BallBehavior").myOwner
= null;
}
}
function teamHasTheBall():boolean{
return
transform.parent.GetComponent(SoccerTeam).hasTheBall;
}
function isPC():boolean{
return transform.parent.GetComponent(SoccerTeam).isPC;
}
// Require a character controller to be attached to the same game
object
@script RequireComponent(CharacterController)
@script AddComponentMenu("Third Person Player/PCThird Person
Controller")
34
Script 6 - PCThirdPersonController.js
// ThirdPersonController.js
var soccerBall:Transform;
var targetGoal:Transform;
// The speed when walking
var walkSpeed = 9.0;
// after trotAfterSeconds of walking we trot with trotSpeed
var trotSpeed = 10.0;
var kickSpeed = 40;
var passSpeed = 20;
// The gravity for the character
var gravity = 20.0;
var speedSmoothing = 10.0;
var rotateSpeed = 500.0;
var trotAfterSeconds = 3.0;
// The camera doesnt start following the target immediately but
waits for a split second to avoid too much waving around.
private var lockCameraTimer = 0.0;
// The current move direction in x-z
35
private var moveDirection = Vector3.zero;
// The current vertical speed
private var verticalSpeed = 0.0;
// The current x-z move speed
private var moveSpeed = 0.0;
// The last collision flags returned from controller.Move
private var collisionFlags : CollisionFlags;
// Is the user pressing any keys?
private var isMoving = false;
// When did the user start walking (Used for going into trot after a
while)
private var walkTimeStart = 0.0;
private var isControllable = true;
function Awake ()
{
moveDirection =
transform.TransformDirection(Vector3.forward);
targetGoal =
transform.parent.GetComponent(SoccerTeam).targetGoal;
soccerBall = GameObject.FindWithTag
("SoccerBall").transform;
}
36
// This next function responds to the "HidePlayer" message by
hiding the player.
// The message is also 'replied to' by identically-named functions in
the collision-handling scripts.
// - Used by the LevelStatus script when the level completed
animation is triggered.
function HidePlayer()
{
GameObject.Find("rootJoint").GetComponent(SkinnedMeshRenderer
).enabled = false; // stop rendering the player.
isControllable = false; // disable player controls.
}
// This is a complementary function to the above. We don't use it in
the tutorial, but it's included for
// the sake of completeness. (I like orthogonal APIs; so sue me!)
function ShowPlayer()
{
GameObject.Find("rootJoint").GetComponent(SkinnedMeshRenderer
).enabled = true; // start rendering the player again.
isControllable = true; // allow player to control the character
again.
}
function UpdateSmoothedMovementDirection ()
{
var cameraTransform = Camera.main.transform;
var grounded = IsGrounded();
37
// Forward vector relative to the camera along the x-z plane
var forward =
cameraTransform.TransformDirection(Vector3.forward);
forward.y = 0;
forward = forward.normalized;
// Right vector relative to the camera
// Always orthogonal to the forward vector
var right = Vector3(forward.z, 0, -forward.x);
var v = Input.GetAxisRaw("Vertical");
var h = Input.GetAxisRaw("Horizontal");
// Are we moving backwards or looking backwards
if (v < -0.2)
movingBack = true;
else
movingBack = false;
var wasMoving = isMoving;
isMoving = Mathf.Abs (h) > 0.1 || Mathf.Abs (v) > 0.1;
// Target direction relative to the camera
var targetDirection = h * right + v * forward;
// Grounded controls
if (grounded)
{
// Lock camera for short period when transitioning
moving & standing still
38
lockCameraTimer += Time.deltaTime;
if (isMoving != wasMoving)
lockCameraTimer = 0.0;
// We store speed and direction seperately,
// so that when the character stands still we still have a
valid forward direction
// moveDirection is always normalized, and we only
update it if there is user input.
if (targetDirection != Vector3.zero)
{
// If we are really slow, just snap to the target
direction
if (moveSpeed < walkSpeed * 0.9 && grounded)
{
moveDirection = targetDirection.normalized;
}
// Otherwise smoothly turn towards it
else
{
moveDirection =
Vector3.RotateTowards(moveDirection, targetDirection, rotateSpeed
* Mathf.Deg2Rad * Time.deltaTime, 1000);
moveDirection = moveDirection.normalized;
}
}
39
// Smooth the speed based on the current target
direction
var curSmooth = speedSmoothing * Time.deltaTime;
// Choose target speed
//* We want to support analog input but make sure you
cant walk faster diagonally than just forward or sideways
var targetSpeed = Mathf.Min(targetDirection.magnitude,
1.0);
// Pick speed modifier
if (Time.time - trotAfterSeconds > walkTimeStart)
{
targetSpeed *= trotSpeed;
}
else
{
targetSpeed *= walkSpeed;
}
moveSpeed = Mathf.Lerp(moveSpeed, targetSpeed,
curSmooth);
// Reset walk time start when we slow down
if (moveSpeed < walkSpeed * 0.3)
walkTimeStart = Time.time;
}
}
function ApplyGravity ()
{
if (isControllable) // don't move player at all if not controllable.
40
{
if (IsGrounded ())
verticalSpeed = 0.0;
else
verticalSpeed -= gravity * Time.deltaTime;
}
}
function Update() {
if (!isControllable)
{
// kill all inputs if not controllable.
Input.ResetInputAxes();
}
if (Input.GetButton ("Fire1"))
{
kick();
}
if (Input.GetButton ("Fire2"))
{
pass(targetGoal);
}
UpdateSmoothedMovementDirection();
// Apply gravity
// - extra power jump modifies gravity
// - controlledDescent mode modifies gravity
ApplyGravity ();
41
// Calculate actual motion
var movement = moveDirection * moveSpeed + Vector3 (0,
verticalSpeed, 0);
movement *= Time.deltaTime;
// Move the controller
var controller : CharacterController =
GetComponent(CharacterController);
collisionFlags = controller.Move(movement);
transform.rotation = Quaternion.LookRotation(moveDirection);
}
function OnControllerColliderHit (hit : ControllerColliderHit )
{
if (hit.moveDirection.y > 0.01)
return;
wallJumpContactNormal = hit.normal;
if (hit.rigidbody == soccerBall.rigidbody){
if (!playerHasTheBall()){
soccerBall.rigidbody.GetComponent("BallBehavior").myOwner
= transform;
transform.parent.GetComponent(SoccerTeam).hasTheBall =
true;
transform.parent.GetComponent(SoccerTeam).opponentTeam.GetC
omponent(SoccerTeam).hasTheBall = false;
}
42
}
}
function kick(){
var targetDir = targetGoal.position - transform.position;
if
(soccerBall.rigidbody.GetComponent("BallBehavior").myOwner ==
transform ){
if( Vector3.Angle (transform.forward, targetDir)
<150 )
soccerBall.rigidbody.GetComponent("BallBehavior").rigidbody.velocit
y = (targetGoal.position transform.position).normalized*kickSpeed;
else
soccerBall.rigidbody.GetComponent("BallBehavior").rigidbody.velocit
y = transform.TransformDirection(Vector3(0,0,kickSpeed));
soccerBall.rigidbody.GetComponent("BallBehavior").myOwner
= null;
}
}
function pass(receiver:Transform){
var targetDir = receiver.position - transform.position;
if
(soccerBall.rigidbody.GetComponent("BallBehavior").myOwner ==
transform ){
43
if( Vector3.Angle (transform.forward,
targetDir) <130 ){
soccerBall.rigidbody.GetComponent("BallBehavior").rigidbody.velocit
y = targetDir.normalized*passSpeed;
soccerBall.rigidbody.GetComponent("BallBehavior").myOwner
= null;
}
else
soccerBall.rigidbody.GetComponent("BallBehavior").rigidbody.velocit
y = transform.TransformDirection(Vector3(0,0,passSpeed));
soccerBall.rigidbody.GetComponent("BallBehavior").myOwner
= null;
}
}
function IsGrounded () {
return (collisionFlags & CollisionFlags.CollidedBelow) != 0;
}
function playerHasTheBall():boolean{
return
(soccerBall.rigidbody.GetComponent("BallBehavior").myOwner ==
transform);
}
function Reset ()
{
gameObject.tag = "Player";
44
}
// Require a character controller to be attached to the same game
object
@script RequireComponent(CharacterController)
@script AddComponentMenu("Third Person Player/Third Person
Controller")
Script 7 - ThirdPersonController.js
45
Download

Creating a Soccer Game