Long Solo Project (working title)
This is an ongoing solo project that I am working on. This game is a turn base strategy game where units actions are based on their frame data, kind of like a fighting game. All the units attacks will be have an animation with an amount of startup, active, and recovery frames. When a unit performs an attack or action, that unit will perform that action until the animation is finished and then it can act again. As such, this system does not have a strict turn order or rounds. All the unit act and animate at the same time and who goes next is determined by who gets done with their animation first. A unit can also get hit out of their attack animation if they get hit during their startup or recovery frames, which would apply hit stun to that unit.
This is a code sample from the project. It is the C# code for the units in the game.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using System.Linq;
public class BattleManager : MonoBehaviour
{
public static BattleManager Instance { get; private set; }
[HideInInspector]
public bool notPaused = true;
public List<Unit> guys;
public List<Unit> goodGuys;
public List<Unit> badGuys;
//UI stuff
public Text pauseText;
public Text actingUnitText;
public GameObject attackPanel;
public Text[] attackButtons;
public GraphManager graphManager;
Queue<Unit> actingUnits;
Unit actingUnit;
bool findingMove = false;
bool findingAttack = false;
bool findingAttackDirection = false;
int currentMainAttack;
Camera cam;
// Battle Commands Stuff
int timeStamp;
List<BattleCommand> battleCommands;
// Debug
bool forcePauser = false;
private void Awake()
{
if (Instance != null)
{
DestroyImmediate(gameObject);
return;
}
Instance = this;
notPaused = true;
actingUnits = new Queue<Unit>();
cam = GameObject.FindGameObjectWithTag("MainCamera").GetComponent<Camera>();
battleCommands = new List<BattleCommand>();
}
void Update()
{
// If there is still units in acting units or if thier is a current actingUnit
if (forcePauser == false)
{
if (actingUnits.Count > 0 || actingUnit != null)
{
notPaused = false;
pauseText.text = "Paused";
if (actingUnit == null)
{
actingUnit = actingUnits.Dequeue();
if (!actingUnit.IsIdleAnimation() || actingUnit.HasActivePath() || actingUnit.HasHitStun())
{
actingUnit = null;
}
}
if (actingUnit != null)
{
actingUnitText.text = ("The Current Acting Unit is: " + actingUnit.name);
if (goodGuys.Contains(actingUnit))
{
if (findingMove)
{
if (Input.GetMouseButtonDown(0))
{
RaycastHit2D hit;
hit = Physics2D.Raycast(new Vector2(cam.ScreenToWorldPoint(Input.mousePosition).x,
cam.ScreenToWorldPoint(Input.mousePosition).y), Vector2.zero, 0f, 1 << 10 | 1 << 11);
if (hit)
{
if (hit.collider.gameObject.layer == 10)
{
Node goal = hit.collider.gameObject.GetComponent<Node>();
Node[] returnPath = actingUnit.GetPathAndMove(goal);
BattleCommand battleCommand = AddNewBattleCommand(actingUnit, timeStamp, returnPath, goal, null);
GraphToMovementGraph(battleCommand);
if (returnPath.Length > 0)
{
findingMove = false;
actingUnit = null;
}
}
}
}
}
if (findingAttack)
{
attackPanel.SetActive(true);
int length = actingUnit.attackManager.mainAttacks.Length;
for (int i = 0; i < length; i++)
{
attackButtons[i].text = actingUnit.attackManager.mainAttacks[i];
}
if (findingAttackDirection)
{
//print ("findingAttackDirection");
if (Input.GetMouseButtonDown (0))
{
//print ("someone pressed the button");
RaycastHit2D hit;
hit = Physics2D.Raycast (new Vector2 (cam.ScreenToWorldPoint (Input.mousePosition).x,
cam.ScreenToWorldPoint (Input.mousePosition).y), Vector2.zero, 0f, 1 << 10 | 1 << 11);
bool hitCardnalNode = false;
Node attackNode = hit.collider.gameObject.GetComponent<Node> ();
if (hit)
{
print ("hit a node");
foreach (Node node in actingUnit.currentNode.cardnalConnections)
{
if (attackNode == node)
{
hitCardnalNode = true;
}
}
}
if (hitCardnalNode)
{
print ("hitCardnalNode is not null");
Vector2 attackDir = attackNode.transform.position - actingUnit.currentNode.transform.position;
attackDir.Normalize ();
print ("attackNode.transform.position " + attackNode.transform.position);
print ("actingUnit.currentNode.position " + actingUnit.currentNode.transform.position);
print (attackDir);
if (attackDir == new Vector2 (1, 0))
{
GetAttack (Attack.Direction.RIGHT);
}
else if (attackDir == new Vector2 (-1, 0))
{
GetAttack (Attack.Direction.LEFT);
}
else if (attackDir == new Vector2 (0, 1))
{
print ("attacking up");
GetAttack (Attack.Direction.UP);
}
else if (attackDir == new Vector2 (0, -1))
{
GetAttack (Attack.Direction.DOWN);
}
}
}
}
}
else
{
attackPanel.SetActive(false);
}
}
else if (badGuys.Contains(actingUnit))
{
BattleCommand battleCommand = actingUnit.GetComponent<BattleAI>().DoBattleCommand(actingUnit, timeStamp);
AddNewBattleCommand(battleCommand);
GraphToMovementGraph(battleCommand);
actingUnit = null;
}
//Calculate possible collision
FindCollisions();
}
}
// NOTE: the turn system is getting better
// be careful of else statements. understand when in a frame the game is
// making its checks. some checks are being made on the next frame instead of on
// the same frame.
if (actingUnit == null)
{
notPaused = true;
timeStamp++;
graphManager.ChangeLowestPossibleFrame(timeStamp);
}
}
else
{
notPaused = false;
}
if (Input.GetKeyDown(KeyCode.P))
{
DebugForcePause(true);
}
}
void LateUpdate()
{
//print("Battle Manager Late Update");
// NOTE: If the game is notPaused, then their is no current acting units and I need to
// search for some
if (notPaused)
{
pauseText.text = "Not Paused";
if (actingUnits.Count == 0)
{
EnqueueUnits(guys);
}
}
}
void FindCollisions()
{
// grab a unit
foreach (Unit unit in guys)
{
// grab a unit to compare the first unit to
foreach (Unit testunit in guys)
{
if (testunit != unit) // make sure we are not testing units against themselves
{
// make sure they have graphs
if (unit.movementGraph != null && testunit.movementGraph != null)
{
if (unit.movementGraph.Count > 0 && testunit.movementGraph.Count > 0)
{
int unitStartingIndex = 0;
int testunitStartingIndex = 0;
bool breakTime = false;
for (int ui = 0;
ui < unit.movementGraph.Count;
++ui)
{
for (int ti = 0;
ti < testunit.movementGraph.Count;
++ti)
{
if (unit.movementGraph[ui].Item1 ==
testunit.movementGraph[ti].Item1)
{
unitStartingIndex = ui;
testunitStartingIndex = ti;
breakTime = true;
break;
}
if (breakTime)
{
break;
}
}
}
while (unit.movementGraph.Count - 1 > unitStartingIndex &&
testunit.movementGraph.Count - 1 >= testunitStartingIndex)
{
Node unitNode = unit.movementGraph[unitStartingIndex].Item2;
Node testunitNode = testunit.movementGraph[testunitStartingIndex].Item2;
Node testunitFramePrev = testunit.movementGraph[testunitStartingIndex].Item2;
// NOTE(barret): we need to get previous node, not the frame
for (int graphIndex = testunitStartingIndex;
graphIndex > 0;
--graphIndex)
{
Node test = testunit.movementGraph[graphIndex].Item2;
if (test != testunitFramePrev)
{
testunitFramePrev = testunit.movementGraph[graphIndex].Item2;
}
}
if (unitNode == testunitNode)
{
unit.FindFirstCollisionNode(unitNode);
testunit.FindFirstCollisionNode(testunitNode);
break;
}
else if (unitNode == testunitFramePrev)
{
unit.FindFirstCollisionNode(unitNode);
testunit.FindFirstCollisionNode(testunitFramePrev);
break;
}
unitStartingIndex++;
testunitStartingIndex++;
}
}
}
}
}
}
}
void GraphToMovementGraph(BattleCommand battleCommand)
{
actingUnit.movementGraph = CalculateAllFuturePositionsByFrame(battleCommand);
if (actingUnit.movementGraph.Count > 0)
{
//Figure out how to do this now
int finalFrame = actingUnit.movementGraph.Last().Item1;
int actingUnitIndex = guys.IndexOf(actingUnit);
graphManager.TestForHighestPossibleFrameChange(finalFrame);
graphManager.sliders[actingUnitIndex].value = finalFrame;
}
}
public void DebugForcePause(bool doIt)
{
if (doIt)
{
forcePauser = true;
print("Force Pausing");
}
}
private void EnqueueUnits(List<Unit> unitGroup)
{
foreach (Unit unit in unitGroup)
{
if (unit.IsIdleAnimation() && !unit.HasActivePath() && !unit.HasHitStun())
{
actingUnits.Enqueue(unit);
}
}
}
public void MakeMoveCommand()
{
if (actingUnit != null)
{
findingMove = true;
findingAttack = false;
}
}
public void MakeAttackCommand()
{
if (actingUnit != null)
{
if (actingUnit.IsIdleAnimation())
{
findingAttack = true;
findingMove = false;
}
}
}
public void ChoseAttack(int mainAttackNumber)
{
findingAttackDirection = true;
currentMainAttack = mainAttackNumber;
}
void GetAttack(Attack.Direction dir)
{
AttackManager attackManager = GetComponent<AttackManager> ();
for(int attackIndex = 0;
attackIndex < attackManager.attacks.Length;
attackIndex++)
{
print ("attackIndex " + attackIndex);
Attack attack = attackManager.attacks[attackIndex];
if (attack.mainAttackFamily == attackManager.mainAttacks[currentMainAttack])
{
if (attack.direction == dir)
{
ChoseAttack (attackIndex);
}
}
}
}
void SendAttack(int attackNumber)
{
Attack newAttack = actingUnit.Attack(attackNumber);
actingUnit = null;
findingAttack = false;
findingAttackDirection = false;
AddNewBattleCommand(actingUnit, timeStamp, null, null, newAttack);
}
public void RemoveUnit(Unit unit)
{
guys.Remove(unit);
}
public BattleCommand AddNewBattleCommand(Unit unit, int time, Node[] path, Node goal, Attack attack)
{
BattleCommand newCommand = new BattleCommand();
newCommand.unit = unit;
newCommand.timeStamp = time;
newCommand.path = path;
newCommand.goal = goal;
newCommand.attack = attack;
battleCommands.Add(newCommand);
return (newCommand);
}
void AddNewBattleCommand(BattleCommand battleCommand)
{
battleCommands.Add(battleCommand);
}
public Node CalculateNodeOnFrame(BattleCommand command, int frame)
{
Node nodeToFrame = null;
Unit unit = command.unit;
Node futureCurrentNodes = unit.currentNode;
if (command.path.Length > 0)
{
int startingTimeSteps = timeStamp;
Vector2 futurePositions = new Vector2(unit.transform.position.x, unit.transform.position.y);
Node futureFromNode = unit.fromNode;
Node[] futureActivePath = command.path;
int futureActivePathIndex = 0;
Node futureActiveNode = futureActivePath[futureActivePathIndex];
for (int currentFrame = startingTimeSteps;
currentFrame != startingTimeSteps + frame;
currentFrame++)
{
Vector2 moveDir = futureActiveNode.gameObject.transform.position -
futureFromNode.gameObject.transform.position;
futurePositions += (moveDir * Time.deltaTime * unit.baseSpeed);
float radius = 0.1f;
Vector2 pV2 = futurePositions;
Vector2 tV2 = futureActiveNode.gameObject.transform.position;
float d2 = Unit.DistanceFormula(pV2, tV2);
float r2 = radius * radius;
if (d2 < r2)
{
futureCurrentNodes = futureActiveNode;
futureFromNode = futureCurrentNodes;
if (futureCurrentNodes == unit.goalNode)
{
print("frame is too late. path already ended");
nodeToFrame = futureCurrentNodes;
break;
}
futureActivePathIndex++;
futureActiveNode = futureActivePath[futureActivePathIndex];
}
nodeToFrame = futureCurrentNodes;
}
}
return (nodeToFrame);
}
List<Tuple<int, Node>> CalculateAllFuturePositionsByFrame(BattleCommand command)
{
List<Tuple<int, Node>> frameToNodeList = new List<Tuple<int, Node>>();
Unit unit = command.unit;
Node futureCurrentNodes = unit.currentNode;
if (command.path != null)
{
int startingTimeSteps = timeStamp;
Vector2 futurePositions = new Vector2(unit.transform.position.x, unit.transform.position.y);
Node futureFromNode = unit.fromNode;
Node[] futureActivePath = command.path;
int futureActivePathIndex = 0;
Node futureActiveNode = futureActivePath[futureActivePathIndex];
futureActivePathIndex++;
int currentFrame = startingTimeSteps;
bool running = true;
while(running)
{
Vector2 moveDir = futureActiveNode.gameObject.transform.position -
futureFromNode.gameObject.transform.position;
futurePositions += (moveDir * Time.deltaTime * unit.baseSpeed);
float radius = 0.1f;
Vector2 pV2 = futurePositions;
Vector2 tV2 = futureActiveNode.gameObject.transform.position;
float d2 = Unit.DistanceFormula(pV2, tV2);
float r2 = radius * radius;
if (d2 < r2)
{
futurePositions = futureActiveNode.transform.position;
futureCurrentNodes = futureActiveNode;
futureFromNode = futureCurrentNodes;
if (futureCurrentNodes == command.goal)
{
Tuple<int, Node> newItem = new Tuple<int,Node>(currentFrame, futureCurrentNodes);
frameToNodeList.Add(newItem);
running = false;
}
if (running == true)
{
futureActiveNode = futureActivePath[futureActivePathIndex];
futureActivePathIndex++;
}
}
if (running)
{
Tuple<int, Node> newItem = new Tuple<int, Node>(currentFrame, futureCurrentNodes);
frameToNodeList.Add(newItem);
currentFrame++;
}
}
}
return (frameToNodeList);
}
void OnDrawGizmos()
{
if (actingUnit != null)
{
Gizmos.color = Color.red;
Gizmos.DrawWireCube(actingUnit.gameObject.transform.position, new Vector3(actingUnit.currentNode.diameter, actingUnit.currentNode.diameter, 0));
}
}
}
public class BattleCommand
{
public Unit unit;
public int timeStamp;
public Node[] path;
public Node goal;
public Attack attack;
public BattleCommand()
{
}
public BattleCommand(Unit u, int t, Node[] p, Node g, Attack a)
{
unit = u;
timeStamp = t;
path = p;
goal = g;
attack = a;
}
}
Knight Arena
Knight Arena is a solo project that I completed in a week. I made the game in Löve2D, coding in LUA. The game is a 4 player competitive game where each player tries to kill the other players for points by charging into the back or sides of the other players.
tile = {}
map={
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
}
player1 = {id = "player1", x, y, img, width, height, speed, facing = {x,y}, canMove = true, isMovingX = false, isMovingY = false, score = 0, isCharging = false, chargeTimerStart = 0, chargeTimer = 0.3, isRebounding = false, reboundTimerStart = 0, reboundTimer = 0.5, isDead = false, deathTimerStart = 0, deathTimer = 2}
player2 = {id = "player2", x, y, img, width, height, speed, facing = {x,y}, canMove = true, isMovingX = false, isMovingY = false, score = 0, isCharging = false, chargeTimerStart = 0, chargeTimer = 0.3, isRebounding = false, reboundTimerStart = 0, reboundTimer = 0.5, isDead = false, deathTimerStart = 0, deathTimer = 2}
player3 = {id = "player3", x, y, img, width, height, speed, facing = {x,y}, canMove = true, isMovingX = false, isMovingY = false, score = 0, isCharging = false, chargeTimerStart = 0, chargeTimer = 0.3, isRebounding = false, reboundTimerStart = 0, reboundTimer = 0.5, isDead = false, deathTimerStart = 0, deathTimer = 2}
player4 = {id = "player4", x, y, img, width, height, speed, facing = {x,y}, canMove = true, isMovingX = false, isMovingY = false, score = 0, isCharging = false, chargeTimerStart = 0, chargeTimer = 0.3, isRebounding = false, reboundTimerStart = 0, reboundTimer = 0.5, isDead = false, deathTimerStart = 0, deathTimer = 2}
players = {player1, player2, player3, player4}
spawnPoint1 = {x = 32, y = 32, width = 32, height = 32}
spawnPoint2 = {x = 640, y = 32, width = 32, height = 32}
spawnPoint3 = {x = 32, y = 640, width = 32, height = 32}
spawnPoint4 = {x = 640, y = 640, width = 32, height = 32}
spawnPoints = {spawnPoint1, spawnPoint2, spawnPoint3, spawnPoint4}
killPoints = 10
joysticks = {}
playArea = {x = 32, y = 32, width = (love.graphics.getWidth( ) - 64), height = (love.graphics.getHeight( ) - 64) }
function draw_map()
for y = 1, 20, 1 do
for x = 1, 20, 1 do
love.graphics.draw(tile[map[x][y]], x * 32, y * 32)
end
end
end
-- Collision detection function.
-- Returns true if two boxes overlap, false if they don't
-- x1,y1 are the left-top coords of the first box, while w1,h1 are its width and height
-- x2,y2,w2 & h2 are the same, but for the second box
function CheckCollision(x1,y1,w1,h1, x2,y2,w2,h2)
return x1 < x2+w2 and
x2 < x1+w1 and
y1 < y2+h2 and
y2 < y1+h1
end
function ResetBoolsAndTimers(player)
player.isCharging = false
player.chargeTimerStart = 0
player.isRebounding = false
player.reboundTimerStart = 0
--player.canMove = true
end
function SpawnPointCollision()
print("entered SpawnPointCollision")
--print(#spawnPoints)
for u = 1, #spawnPoints, 1 do
local locationBad = false
local spawnPointu = spawnPoints[u]
print("spawnPoint " .. spawnPointu.x)
for i = 1, #players, 1 do
local playeri = players[i]
local hit = CheckCollision( playeri.x, playeri.y, playeri.width, playeri.height, spawnPointu.x, spawnPointu.y, spawnPointu.width, spawnPointu.height)
if hit then
locationBad = true
end
end
if locationBad == false then
return spawnPointu.x, spawnPointu.y
end
end
end
function PlayerDeath(player, dt)
ResetBoolsAndTimers(player)
if player.deathTimerStart < player.deathTimer then
player.canMove = false
player.deathTimerStart = player.deathTimerStart + (1 * dt)
else
local spawnX, spawnY = SpawnPointCollision()
player.deathTimerStart = 0
player.x = spawnX
player.y = spawnY
player.canMove = true
player.isDead = false
end
end
function PlayerCharge(player, dt)
if player.chargeTimerStart < player.chargeTimer then
--print("Charge facing " .. player.facing.x .. "," .. player.facing.y)
player.x = player.x + player.facing.x * (player.speed * 15) * dt
player.y = player.y + player.facing.y * (player.speed * 15) * dt
player.canMove = false
player.chargeTimerStart = player.chargeTimerStart + (1 * dt)
else
player.isCharging = false
player.chargeTimerStart = 0
player.canMove = true
end
end
function Reboud(player, dt)
--print ("I get called for " .. player.id)
if player.reboundTimerStart < player.reboundTimer then
player.reboundTimerStart = player.reboundTimerStart + (1 * dt)
player.x = player.x + (-1 * player.facing.x) * (player.speed * 5) * dt
player.y = player.y + (-1 * player.facing.y) * (player.speed * 5) * dt
player.canMove = false
else
player.reboundTimerStart = 0
player.canMove = true
player.isRebounding = false
end
end
function ReboundSetUp(playeri, playeru)
-- the setup is wront right now
-- i need to have players facing be based on where they hit each other.
-- not by their current facing
-- need to figure out if a value should be set to zero
ResetBoolsAndTimers(playeri)
ResetBoolsAndTimers(playeru)
local priority = nil
-- priority is set to whoever is moving and not set if both are moving
if (playeri.isMovingX or playeri.isMovingY) then
priority = playeri
end
if (playeru.isMovingX or playeru.isMovingY) and priority == nil then
priority = playeru
else
priority = nil
end
-- if a player is moving diagonally
if(playeri.isMovingX and playeri.isMovingY) then
priority = playeri
elseif (playeru.isMovingX and playeru.isMovingY) and not (playeri.isMovingX and player.isMovingY) then
priority = playeru
end
-- playeri is set to priority if it is charging
if playeri.isCharging then
priority = playeri
end
-- but if playeru is also charging, set priority to no one
if playeru.isCharging and (priority == playeri and playeri.isCharging)then
if(playeri.isMovingX and player.isMovingY) then --if one is charging diagonally
priority = playeri
elseif (playeru.isMovingX and playeru.isMovingY) and not (playeri.isMovingX and player.isMovingY) then
priority = playeru
else -- if neither player is charging diagonally
priority = nil
end
else -- if playeri is not charging, set priority to playeru
priority = playeru
end
if not priority == nil then
if priority == playeri then
playeru.facing.x = playeri.facing.x * -1
playeru.facing.y = playeri.facing.y * -1
playeri.facing.x = playeri.facing.x * -1
playeri.facing.y = playeri.facing.y * -1
else
playeri.facing.x = playeru.facing.x * -1
playeri.facing.y = playeru.facing.y * -1
playeru.facing.x = playeru.facing.x * -1
playeru.facing.y = playeru.facing.y * -1
end
else
playeri.facing.x = playeri.facing.x * -1
playeri.facing.y = playeri.facing.y * -1
playeru.facing.x = playeru.facing.x * -1
playeru.facing.y = playeru.facing.y * -1
end
playeri.isRebounding = true
playeru.isRebounding = true
end
function AreTheyFacingEachOther(playeri, playeru)
local Xfacing = false
local Yfacing = false
if (playeri.facing.x == 1 and playeru.facing.x == -1) or (playeri.facing.x == 1 and playeru.facing.x == -1) or (playeri.facing.x == 0 and playeru.facing.x == 0)then
Xfacing = true
end
if (playeri.facing.y == 1 and playeru.facing.y == -1) or (playeri.facing.y == 1 and playeru.facing.y == -1) or (playeri.facing.y == 0 and playeru.facing.y == 0)then
Yfacing = true
end
if Xfacing == true and Yfacing == true then
return true
else
return false
end
end
function IsOneFacingTheOther(testPlayer, testAgainstPlayer)
local Xfacing = false
local Yfacing = false
if testPlayer.x - testAgainstPlayer.x > 0 and testPlayer.facing.x == -1 then
Xfacing = true
elseif testPlayer.x - testAgainstPlayer.x < 0 and testPlayer.facing.x == 1 then
Xfacing = true
elseif testPlayer.facing.x == 0 then
Xfacing = true
end
if testPlayer.y - testAgainstPlayer.y > 0 and testPlayer.facing.y == -1 then
Yfacing = true
elseif testPlayer.y - testAgainstPlayer.y < 0 and testPlayer.facing.y == 1 then
Yfacing = true
elseif testPlayer.facing.y == 0 then
Yfacing = true
end
if Xfacing == true and Yfacing == true then
return true
else
return false
end
end
function GivePoint(player)
player.score = player.score + killPoints
end
function PlayerCollision()
for i = 1, #players, 1 do
for u = 1, #players, 1 do
if players[i] ~= players[u] then
local playeri = players[i]
local playeru = players[u]
local hit = CheckCollision( playeri.x, playeri.y, playeri.width, playeri.height, playeru.x, playeru.y, playeru.width, playeru.height)
if hit then
if playeri.isCharging then
--print("I Collided were charging")
if IsOneFacingTheOther(playeri, playeru) and not IsOneFacingTheOther(playeru, playeri) then
--print("IsOneFacingTheOther works as intended")
playeru.isDead = true
--print (playeru.isDead)
GivePoint(playeri)
end
elseif playeru.isCharging then
if IsOneFacingTheOther(playeru, playeri) and not IsOneFacingTheOther(playeri, playeru) then
playeri.isDead = true
GivePoint(playeru)
end
end
ReboundSetUp(playeri, playeru)
end
end
end
end
end
function WallCollision(dt)
for i = 1, #players, 1 do
local player = players[i]
--print(player.id)
local hit = CheckCollision(player.x, player.y, player.width, player.height, playArea.x, playArea.y, playArea.width, playArea.height)
if not hit then
ResetBoolsAndTimers(player)
--player.isRebounding = true
--print ("hit wall")
player.isDead = true
else
--print("not hit will")
end
end
end
function DrawPlayers()
if not player1.isDead then
love.graphics.draw(player1.img, player1.x, player1.y)
end
if not player2.isDead then
love.graphics.draw(player2.img, player2.x, player2.y)
end
if not player3.isDead then
love.graphics.draw(player3.img, player3.x, player3.y)
end
if not player4.isDead then
love.graphics.draw(player4.img, player4.x, player4.y)
end
end
function PlayerStatuses(dt)
for i = 1, #players, 1 do
local playerWithStatus = players[i]
if playerWithStatus.isRebounding then
Reboud(playerWithStatus, dt)
end
if playerWithStatus.isCharging == true then
PlayerCharge(playerWithStatus, dt)
end
if playerWithStatus.isDead == true then
PlayerDeath(playerWithStatus, dt)
end
end
end
function NewPlayerInput(dt)
for i = 1, #joysticks, 1 do
local joystick = joysticks[i] --Only gets players with controllers connected
local player = players[joystick:getID()]
local directionX = joystick:getGamepadAxis("leftx")
local directionY = joystick:getGamepadAxis("lefty")
if joystick:isGamepadDown("a") then
player.isCharging = true
end
if player.canMove then
if joystick:isGamepadDown("dpup") or directionY < -0.5 then
player.y = player.y - player.speed * dt
player.facing.y = -1
player.isMovingY = true
if (not joystick:isGamepadDown("dpleft") and not joystick:isGamepadDown("dpright")) and (not (directionX < -0.5) and not (directionX > 0.5)) then
--print ("What about this")
player.facing.x = 0
end
elseif joystick:isGamepadDown("dpdown") or directionY > 0.5 then
player.y = player.y + player.speed * dt
player.facing.y = 1
player.isMovingY = true
if (not joystick:isGamepadDown("dpleft") and not joystick:isGamepadDown("dpright")) and (not (directionX < -0.5) and not (directionX > 0.5)) then
player.facing.x = 0
end
else
player.isMovingY = false
end
if joystick:isGamepadDown("dpleft") or directionX < -0.5 then
player.x = player.x - player.speed * dt
player.facing.x = -1
player.isMovingX = true
if (not joystick:isGamepadDown("dpup") and not joystick:isGamepadDown("dpdown")) and (not (directionY < -0.5) and not (directionY > 0.5)) then
player.facing.y = 0
end
elseif joystick:isGamepadDown("dpright") or directionX > 0.5 then
player.x = player.x + player.speed * dt
player.facing.x = 1
player.isMovingX = true
if (not joystick:isGamepadDown("dpup") and not joystick:isGamepadDown("dpdown")) and (not (directionY < -0.5) and not (directionY > 0.5)) then
player.facing.y = 0
end
else
player.isMovingX = false
end
end
end
end
function love.load()
for i=0,3 do -- change 3 to the number of tile images minus 1.
tile[i] = love.graphics.newImage( "imgs/tile"..i..".png" )
end
player1.x = 32
player1.y = 32
player1.img = love.graphics.newImage("imgs/player1.png")
player1.width = player1.img:getWidth()
player1.height = player1.img:getHeight()
player1.speed = 64
player1.facing.x = 1
player1.facing.y = -1
player2.x = 640
player2.y = 32
player2.img = love.graphics.newImage("imgs/player2.png")
player2.width = player2.img:getWidth()
player2.height = player2.img:getHeight()
player2.speed = 64
player2.facing.x = -1
player2.facing.y = 1
player3.x = 32
player3.y = 640
player3.img = love.graphics.newImage("imgs/player3.png")
player3.width = player3.img:getWidth()
player3.height = player3.img:getHeight()
player3.speed = 64
player3.facing.x = -1
player3.facing.y = 1
player4.x = 640
player4.y = 640
player4.img = love.graphics.newImage("imgs/player4.png")
player4.width = player4.img:getWidth()
player4.height = player4.img:getHeight()
player4.speed = 64
player4.facing.x = -1
player4.facing.y = 1
local joystickcount = love.joystick.getJoystickCount()
print("The amount of joysticks is " .. joystickcount)
joysticks = love.joystick.getJoysticks( )
for i = 1, #joysticks, 1 do
id, instanceid = joysticks[i]:getID()
print("This controller is " .. id)
end
end
function love.update(dt)
PlayerCollision(dt)
WallCollision(dt)
NewPlayerInput(dt)
PlayerStatuses(dt)
end
function love.draw()
draw_map()
DrawPlayers()
end
